package view_server

import (
	"bigdevops/src/cache"
	"bigdevops/src/common"
	"bigdevops/src/config"
	"bigdevops/src/models"
	"bufio"
	"bytes"
	"context"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"go.uber.org/zap"
	"io"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/util/json"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/tools/remotecommand"
	resourcehelper "k8s.io/kubectl/pkg/util/resource"
	"net/http"
	"sigs.k8s.io/yaml"
	"sort"
	"strconv"
	"strings"
	"unicode/utf8"
)

var (
	wsLogUpgrade = websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
)

func getK8sPodListByNs(c *gin.Context) {

	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	currentPage, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	sortFiled := c.DefaultQuery("field", "")
	orderType := c.DefaultQuery("order", "")
	//offset := 0
	//limit := 0
	//limit = pageSize
	//if currentPage > 1 {
	//	offset = (currentPage - 1) * limit
	//}
	//
	//fmt.Println(offset)
	// 这里只能新增 不能去掉，因为是 多种资源共用的query
	//searchUserID := c.DefaultQuery("UserID", "")
	//searchUserIDInt, _ := strconv.Atoi(searchUserID)
	//searchName := c.DefaultQuery("name", "")
	// 集群的名称
	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("name", "")

	searchNamespace := c.DefaultQuery("namespace", "")
	if searchNamespace == common.K8S_NS_ALL_KEY {
		searchNamespace = ""
	}

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	mSet := kc.GetClusterMetricsClientSetById(dbObj.ID)
	if mSet == nil {
		sc.Logger.Error("根据id找k8s集群metricsSet缓存错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	ctx1, cancel1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer cancel1()
	podItems, err := kSet.CoreV1().Pods(searchNamespace).List(ctx1, metav1.ListOptions{})
	if err != nil {
		sc.Logger.Error("根据ik8s集群kset获取节点错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 进行搜索
	filterPods := []corev1.Pod{}
	for _, pod := range podItems.Items {
		if searchName != "" && !strings.Contains(pod.Name, searchName) {
			continue
		}
		filterPods = append(filterPods, pod)

	}

	//startIndex, endIndex
	startIndex := (pageSize) * (currentPage - 1)
	endIndex := startIndex + pageSize
	if endIndex > len(filterPods) {
		endIndex = len(filterPods)
	}

	// 转化一下
	myPods := []*OnePod{}
	pageResult := filterPods[startIndex:endIndex]

	for _, pod := range pageResult {
		myPod := podConvert(pod)
		myPods = append(myPods, myPod)
	}
	// 排序
	if sortFiled == "name" {

		sort.SliceStable(myPods, func(i, j int) bool {
			if orderType == "ascend" {
				return myPods[i].Name < myPods[j].Name
			} else {
				return myPods[i].Name > myPods[j].Name
			}

		})
	}
	if sortFiled == "restarts" {

		sort.SliceStable(myPods, func(i, j int) bool {
			if orderType == "ascend" {
				return myPods[i].Restarts < myPods[j].Restarts
			} else {
				return myPods[i].Restarts > myPods[j].Restarts
			}

		})
	}

	if sortFiled == "age" {

		sort.SliceStable(myPods, func(i, j int) bool {
			if orderType == "ascend" {
				return myPods[i].Age < myPods[j].Age
			} else {
				return myPods[i].Age > myPods[j].Age
			}

		})
	}

	if sortFiled == "cpuRequestInfo" {

		sort.SliceStable(myPods, func(i, j int) bool {
			if orderType == "ascend" {
				return myPods[i].CpuRequestInfo < myPods[j].CpuRequestInfo
			} else {
				return myPods[i].CpuRequestInfo > myPods[j].CpuRequestInfo
			}

		})
	}

	resp := &ResponseResourceCommon{
		//Total: models.GetK8sClusterCount(), 因为是带了查询条件的 所以 count 不能是all 而是 过滤后的total

		Total: len(filterPods),
		Items: myPods,
	}

	common.OkWithDetailed(resp, "ok", c)
}

func getK8sPodListByDeploy(c *gin.Context) {

	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	currentPage, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	sortFiled := c.DefaultQuery("field", "")
	orderType := c.DefaultQuery("order", "")
	//offset := 0
	//limit := 0
	//limit = pageSize
	//if currentPage > 1 {
	//	offset = (currentPage - 1) * limit
	//}
	//
	//fmt.Println(offset)
	// 这里只能新增 不能去掉，因为是 多种资源共用的query
	//searchUserID := c.DefaultQuery("UserID", "")
	//searchUserIDInt, _ := strconv.Atoi(searchUserID)
	//searchName := c.DefaultQuery("name", "")
	// 集群的名称
	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("name", "")
	searchApplication := c.DefaultQuery("application", "")
	searchInstance := c.DefaultQuery("instance", "")

	searchNamespace := c.DefaultQuery("namespace", "")

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	mSet := kc.GetClusterMetricsClientSetById(dbObj.ID)
	if mSet == nil {
		sc.Logger.Error("根据id找k8s集群metricsSet缓存错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	ctx1, cancel1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer cancel1()

	ctx1, canFun1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer canFun1()
	labelSelector, _ := fields.ParseSelector(fmt.Sprintf("%v=%v,%v=%v",
		common.K8S_APP_LABEL_APP_NAME, searchApplication,
		common.K8S_APP_LABEL_INS_NAME, searchInstance,
	))
	podItems, err := kSet.CoreV1().Pods(searchNamespace).List(ctx1, metav1.ListOptions{
		LabelSelector: labelSelector.String(),
	})
	if err != nil {
		msg := fmt.Sprintf("根据LabelSelector找k8s-pod错误:%v", labelSelector.String())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 进行搜索
	filterPods := []corev1.Pod{}
	for _, pod := range podItems.Items {
		if searchName != "" && !strings.Contains(pod.Name, searchName) {
			continue
		}
		filterPods = append(filterPods, pod)

	}

	//startIndex, endIndex
	startIndex := (pageSize) * (currentPage - 1)
	endIndex := startIndex + pageSize
	if endIndex > len(filterPods) {
		endIndex = len(filterPods)
	}

	// 转化一下
	myPods := []*OnePod{}
	pageResult := filterPods[startIndex:endIndex]

	for _, pod := range pageResult {
		myPod := podConvert(pod)
		myPods = append(myPods, myPod)
	}
	// 排序
	if sortFiled == "name" {

		sort.SliceStable(myPods, func(i, j int) bool {
			if orderType == "ascend" {
				return myPods[i].Name < myPods[j].Name
			} else {
				return myPods[i].Name > myPods[j].Name
			}

		})
	}
	if sortFiled == "restarts" {

		sort.SliceStable(myPods, func(i, j int) bool {
			if orderType == "ascend" {
				return myPods[i].Restarts < myPods[j].Restarts
			} else {
				return myPods[i].Restarts > myPods[j].Restarts
			}

		})
	}

	if sortFiled == "age" {

		sort.SliceStable(myPods, func(i, j int) bool {
			if orderType == "ascend" {
				return myPods[i].Age < myPods[j].Age
			} else {
				return myPods[i].Age > myPods[j].Age
			}

		})
	}

	if sortFiled == "cpuRequestInfo" {

		sort.SliceStable(myPods, func(i, j int) bool {
			if orderType == "ascend" {
				return myPods[i].CpuRequestInfo < myPods[j].CpuRequestInfo
			} else {
				return myPods[i].CpuRequestInfo > myPods[j].CpuRequestInfo
			}

		})
	}

	resp := &ResponseResourceCommon{
		//Total: models.GetK8sClusterCount(), 因为是带了查询条件的 所以 count 不能是all 而是 过滤后的total

		Total: len(filterPods),
		Items: myPods,
	}

	common.OkWithDetailed(resp, "ok", c)
}

func getK8sPodContainers(c *gin.Context) {

	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("podName", "")

	searchNamespace := c.DefaultQuery("namespace", "")

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	ctx1, cancel1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer cancel1()
	pod, err := kSet.CoreV1().Pods(searchNamespace).Get(ctx1, searchName, metav1.GetOptions{})
	if err != nil {
		sc.Logger.Error("根据k8s集群kset获取pod错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	res := []common.CommonSelectOneItem{}
	for _, c := range pod.Spec.Containers {
		res = append(res, common.CommonSelectOneItem{
			Label: c.Name,
			Value: c.Name,
		})
	}

	common.OkWithDetailed(res, "ok", c)
}

func getPodContainerNormalLog(c *gin.Context) {
	//kset *kubernetes.Clientset, podName string, containerName string, ns string string

	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("podName", "")

	searchNamespace := c.DefaultQuery("namespace", "")
	searchContainer := c.DefaultQuery("container", "")
	logLineString := c.DefaultQuery("logLine", "")
	logLine, _ := strconv.Atoi(logLineString)

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	logOpts := &corev1.PodLogOptions{
		TypeMeta:     metav1.TypeMeta{},
		Container:    searchContainer,
		Follow:       false,
		Previous:     false,
		SinceSeconds: nil,
		SinceTime:    nil,
		Timestamps:   false,
	}

	if logLine > 0 {
		var tailLine *int64
		var tl int64 = 0
		tl = int64(logLine)
		tailLine = &tl
		logOpts.TailLines = tailLine
	}

	req := kSet.CoreV1().Pods(searchNamespace).GetLogs(searchName, logOpts)
	ctx2, canFun2 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer canFun2()
	podLogs, err := req.Stream(ctx2)
	if err != nil {
		msg := fmt.Sprintf("通过Stream获取容器日志失败:%v", err.Error())
		sc.Logger.Error(msg,
			zap.Any("k8s集群配置", searchCluster),
			zap.Any("ns", searchNamespace),
			zap.Any("pod", searchName),
			zap.Any("c", searchContainer),
			zap.Error(err),
		)
		common.FailWithMessage(msg, c)
		return
	}
	defer podLogs.Close()

	buf := new(bytes.Buffer)
	_, err = io.Copy(buf, podLogs)
	if err != nil {
		msg := fmt.Sprintf("通过Stream获取容器日志后io.Copy失败:%v", err.Error())
		sc.Logger.Error(msg,
			zap.Any("k8s集群配置", searchCluster),
			zap.Any("ns", searchNamespace),
			zap.Any("pod", searchName),
			zap.Any("c", searchContainer),
			zap.Error(err),
		)
		common.FailWithMessage(msg, c)
		return
	}

	common.OkWithDetailed(buf.String(), "ok", c)

}

func getPodContainerTailLog(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	//kset *kubernetes.Clientset, podName string, containerName string, ns string string
	// 升级成 websocket 连接
	ws, err := wsLogUpgrade.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		msg := fmt.Sprintf("查看容器日志升级websocket 连接失败:%v", err)
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return

	}
	// 完成时关闭连接释放资源
	defer ws.Close()
	// 处理心跳
	go func() {
		for {
			// 读取客户端发送过来的消息，如果没发就会一直阻塞住
			mt, message, err := ws.ReadMessage()
			if err != nil {

				sc.Logger.Error("读取客户端发送过来的消息错误", zap.Error(err))
				break
			}
			sc.Logger.Debug(fmt.Sprintf("ws.ReadMessage.print messageType:%v msg:%v", mt, string(message)))
			if string(message) == "ping" {
				message = []byte(common.WEBSOCKET_HEARTBEAT_RESP_MSG)
			}
			ws.WriteMessage(1, message)
		}
	}()

	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("podName", "")

	searchNamespace := c.DefaultQuery("namespace", "")
	searchContainer := c.DefaultQuery("container", "")

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	logOpts := &corev1.PodLogOptions{
		TypeMeta:   metav1.TypeMeta{},
		Container:  searchContainer,
		Follow:     true,
		Timestamps: true,
	}

	req := kSet.CoreV1().Pods(searchNamespace).GetLogs(searchName, logOpts)
	podLogs, err := req.Stream(context.Background())
	if err != nil {
		msg := fmt.Sprintf("通过Stream获取容器日志失败:%v", err.Error())
		sc.Logger.Error(msg,
			zap.Any("k8s集群配置", searchCluster),
			zap.Any("ns", searchNamespace),
			zap.Any("pod", searchName),
			zap.Any("c", searchContainer),
			zap.Error(err),
		)
		common.FailWithMessage(msg, c)
		return
	}
	defer podLogs.Close()
	r := bufio.NewReader(podLogs)
	// 不断的按行读取日志，发送即可
	for {
		logBytes, err := r.ReadBytes('\n')

		if err != nil {
			break
		}

		//log.Printf("读取到容器日志:%v", string(logBytes))
		err = ws.WriteMessage(1, logBytes)
		if err != nil {
			sc.Logger.Error("ws写入日志错误", zap.Error(err))
			break
		}
	}
	common.OkWithMessage("ok", c)

}

// 为remotecommand.StreamOptions提供方法
type streamHandler struct {
	ws          *websocket.Conn                 //ws
	inputMsg    chan []byte                     //客户端输入数据
	resizeEvent chan remotecommand.TerminalSize //窗口调整事件
}

// 获取调整窗口事件
func (handler *streamHandler) Next() *remotecommand.TerminalSize {
	resize := <-handler.resizeEvent
	return &resize
}

// 从ws获取客户端输入的数据
// p 就是上层 调用的时候传入 切片 容器
func (handler *streamHandler) Read(p []byte) (size int, err error) {
	data, ok := <-handler.inputMsg
	if !ok {
		return 0, errors.New("I/O data reading failed")
	}
	copy(p, data)
	return len(data), nil
}

// 将标准输出、错误写入ws（客户端）
func (handler *streamHandler) Write(p []byte) (int, error) {
	// 处理非utf8字符
	if !utf8.Valid(p) {
		bufStr := string(p)
		buf := make([]rune, 0, len(bufStr))
		for _, r := range bufStr {
			if r == utf8.RuneError {
				buf = append(buf, []rune("@")...)
			} else {
				buf = append(buf, r)
			}
		}
		p = []byte(string(buf))
	}
	err := handler.ws.WriteMessage(websocket.TextMessage, p)
	return len(p), err
}

// 处理ws输入数据
func dealWithFrontWsData(handler *streamHandler) {
	for {
		_, msg, err := handler.ws.ReadMessage()
		if err != nil {
			return
		}
		//心跳检测
		if string(msg) == "ping" {
			continue
		}
		//调整窗口宽高
		if strings.Contains(string(msg), "resize") {
			resizeSlice := strings.Split(string(msg), ":")
			rows, _ := strconv.Atoi(resizeSlice[1])
			cols, _ := strconv.Atoi(resizeSlice[2])
			handler.resizeEvent <- remotecommand.TerminalSize{
				Width:  uint16(cols),
				Height: uint16(rows),
			}
			continue
		}
		// 真正的前端输入命令
		handler.inputMsg <- msg
	}
}

func getPodContainerWebShell(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	//kset *kubernetes.Clientset, podName string, containerName string, ns string string
	// 升级成 websocket 连接
	ws, err := wsLogUpgrade.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		msg := fmt.Sprintf("容器webshell升级websocket 连接失败:%v", err)
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return

	}
	// 完成时关闭连接释放资源
	defer ws.Close()
	// 处理心跳
	go func() {
		for {
			// 读取客户端发送过来的消息，如果没发就会一直阻塞住
			mt, message, err := ws.ReadMessage()
			if err != nil {

				sc.Logger.Error("读取客户端发送过来的消息错误", zap.Error(err))
				break
			}
			sc.Logger.Debug(fmt.Sprintf("ws.ReadMessage.print messageType:%v msg:%v", mt, string(message)))
			if string(message) == "ping" {
				message = []byte(common.WEBSOCKET_HEARTBEAT_RESP_MSG)
			}

			//ws.WriteMessage(1, message)
		}
	}()

	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("podName", "")

	searchNamespace := c.DefaultQuery("namespace", "")
	searchContainer := c.DefaultQuery("container", "")
	searchShell := c.DefaultQuery("shell", "bash")

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	kConfig := kc.GetClusterKConfigById(dbObj.ID)

	if kConfig == nil {
		sc.Logger.Error("根据id找k8s集群kConfig缓存错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	req := kSet.CoreV1().RESTClient().Post().
		Resource("pods").
		Name(searchName).
		Namespace(searchNamespace).
		SubResource("exec").
		VersionedParams(&corev1.PodExecOptions{
			Container: searchContainer,
			Command:   []string{searchShell},

			Stdin:  true,
			Stdout: true,
			Stderr: true,
			TTY:    true,
		}, scheme.ParameterCodec)

	exec, err := remotecommand.NewSPDYExecutor(kConfig, "POST", req.URL())
	if err != nil {
		//

		msg := "remotecommand.NewSPDYExecutor.err"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}
	// handler 是一个中介  前面 读取前端的命令 ，后面读取k8s exec 返回值
	handler := &streamHandler{
		ws:          ws,
		inputMsg:    make(chan []byte, 1024),
		resizeEvent: make(chan remotecommand.TerminalSize, 1),
	}
	// 异步不断的处理 前端的3种数据
	go dealWithFrontWsData(handler)

	//var stdout, stderr bytes.Buffer
	err = exec.StreamWithContext(context.Background(), remotecommand.StreamOptions{
		Stdin:             handler,
		Stdout:            handler,
		Stderr:            handler,
		TerminalSizeQueue: handler,
		Tty:               true,
	})
	if err != nil {
		msg := fmt.Sprintf("exec.StreamWithContext.err:%v", err.Error())
		sc.Logger.Error(msg, zap.Error(err))
		common.ReqBadFailWithMessage(msg, c)
		ws.WriteMessage(1, []byte(msg))
		ws.Close()
	}

	common.OkWithMessage("ok", c)

}

func getK8sPodYamlOne(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)

	searchCluster := c.DefaultQuery("cluster", "")
	searchName := c.DefaultQuery("podName", "")

	searchNamespace := c.DefaultQuery("namespace", "")
	//searchContainer := c.DefaultQuery("container", "")
	//searchShell := c.DefaultQuery("shell", "bash")

	if searchCluster == "" {
		msg := "集群名称未传入"
		sc.Logger.Error(msg)
		common.ReqBadFailWithMessage(msg, c)
		return
	}

	dbObj, err := models.GetK8sClusterByName(searchCluster)
	if err != nil {
		sc.Logger.Error("根据name找k8s集群错误", zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	// 从cache中通过 集群的id 拿到集群的clientSet
	kc := c.MustGet(common.GIN_CTX_K8s_CACHE).(*cache.K8sClusterCache)
	kSet := kc.GetClusterClientSetById(dbObj.ID)
	if kSet == nil {
		msg := fmt.Sprintf("根据id找k8s集群kset缓存错误")
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	ctx1, cancel1 := common.GenTimeoutContext(dbObj.ActionTimeoutSeconds)
	defer cancel1()
	pod, err := kSet.CoreV1().Pods(searchNamespace).Get(ctx1, searchName, metav1.GetOptions{
		TypeMeta: metav1.TypeMeta{Kind: "Pod", APIVersion: "v1"},
	})
	//fmt.Println(pod)
	pod.APIVersion = "v1"
	pod.Kind = "Pod"
	pod.ManagedFields = nil

	if err != nil {
		msg := fmt.Sprintf("根据id找k8s集群get-pod错误:%v", err.Error())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	jsonBytes, err := json.Marshal(pod)
	if err != nil {
		msg := fmt.Sprintf("根据pod对象jsonMarshal错误:%v", err.Error())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}
	y, err := yaml.JSONToYAML(jsonBytes)
	if err != nil {
		msg := fmt.Sprintf("根据pod对象jsonyaml.JSONToYAML错误:%v", err.Error())
		sc.Logger.Error(msg, zap.Any("k8s集群配置", searchCluster), zap.Error(err))
		common.FailWithMessage(msg, c)
		return
	}

	common.OkWithData(string(y), c)
}

func podConvert(pod corev1.Pod) *OnePod {
	res := &OnePod{}
	res.Namespace = pod.Namespace
	res.Name = pod.Name
	res.Age = translateTimestampSince(pod.CreationTimestamp)

	reason := string(pod.Status.Phase)
	if pod.Status.Reason != "" {
		reason = pod.Status.Reason
	}
	res.Status = reason

	restarts := 0
	readyContainers := 0
	totalContainers := len(pod.Spec.Containers)

	for _, c := range pod.Spec.Containers {
		res.Containers = append(res.Containers, c.Name)

	}

	podReqs, podLimits := resourcehelper.PodRequestsAndLimits(&pod)

	cpuReqs, cpuLimits, memoryReqs, memoryLimits := podReqs[corev1.ResourceCPU], podLimits[corev1.ResourceCPU], podReqs[corev1.ResourceMemory], podLimits[corev1.ResourceMemory]

	for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {

		container := pod.Status.ContainerStatuses[i]
		if container.Ready && container.State.Running != nil {
			readyContainers++
		}
		restarts += int(container.RestartCount)
	}
	res.Ready = fmt.Sprintf("%d/%d", readyContainers, totalContainers)
	res.Ip = pod.Status.PodIP
	res.Restarts = restarts

	res.Image = pod.Spec.Containers[0].Image
	tmp := strings.Split(res.Image, ":")
	res.ImageVersion = tmp[len(tmp)-1]
	res.PodTemplateHash = pod.Labels["pod-template-hash"]
	res.CpuRequestInfo = fmt.Sprintf("%v/%v", cpuReqs.String(), cpuLimits.String())
	res.MemRequestInfo = fmt.Sprintf("%v/%v", memoryReqs.Value()/1024/1024, memoryLimits.Value()/1024/1024)

	return res

}

type OnePod struct {
	Namespace string `json:"namespace"`

	ImageVersion      string   `json:"imageVersion"`
	ImageVersionColor string   `json:"imageVersionColor"`
	PodTemplateHash   string   `json:"podTemplateHash"`
	Image             string   `json:"image"`
	Ip                string   `json:"ip"`
	Restarts          int      `json:"restarts"`
	Status            string   `json:"status"`
	Ready             string   `json:"ready"`
	Name              string   `json:"name"`
	CpuRequestInfo    string   `json:"cpuRequestInfo"`
	MemRequestInfo    string   `json:"memRequestInfo"`
	CpuRequest        string   `json:"cpuRequest"`
	CpuLimit          string   `json:"cpuLimit"`
	MemRequest        string   `json:"memRequest"`
	MemLimit          string   `json:"memLimit"`
	Age               string   `json:"age"`
	Containers        []string `json:"containers"`
}
